use thiserror::Error;
use std::path::PathBuf;

/// 项目转换过程中可能发生的错误
#[derive(Error, Debug)]
pub enum ConversionError {
    #[error("IO错误: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("XML解析错误: {0}")]
    XmlParse(String),
    
    #[error("解析roxmltree文档错误: {0}")]
    RoxmlParseError(#[from] roxmltree::Error),
      #[error("项目文件未找到: {0}")]
    #[allow(dead_code)]
    ProjectNotFound(PathBuf),
    
    #[error("解决方案文件未找到: {0}")]
    SolutionNotFound(PathBuf),
    
    #[error("无效的项目文件格式: {0} ({1})")]
    #[allow(dead_code)]
    InvalidProjectFormat(PathBuf, String),
    
    #[error("无效的解决方案文件格式: {0} ({1})")]
    #[allow(dead_code)]
    InvalidSolutionFormat(PathBuf, String),
    
    #[error("不支持的项目类型: {0}")]
    #[allow(dead_code)]
    UnsupportedProjectType(String),
    
    #[error("创建输出目录失败: {0}")]
    #[allow(dead_code)]
    OutputDirCreationFailed(PathBuf),
    
    #[error("缺少属性: {0}")]
    #[allow(dead_code)]
    MissingProperty(String),
    
    #[error("找不到文件: {0}")]
    FileNotFound(PathBuf),
    
    #[error("源文件复制失败: {0} -> {1}: {2}")]
    FileCopyFailed(PathBuf, PathBuf, String),
      #[error("CMake生成失败: {0}")]
    #[allow(dead_code)]
    CMakeGenerationFailed(String),
    
    #[error("路径解析错误: {0}")]
    #[allow(dead_code)]
    PathParseError(String),
    
    #[error("配置缺失: {0}")]
    #[allow(dead_code)]
    MissingConfiguration(String),
    
    #[error("其他错误: {0}")]
    Other(String),
}

// 从标准XML错误转换
impl From<xml::reader::Error> for ConversionError {
    fn from(err: xml::reader::Error) -> Self {
        ConversionError::XmlParse(err.to_string())
    }
}

/// 转换结果包含警告信息
#[derive(Debug, Default)]
pub struct ConversionWarnings {
    pub missing_files: Vec<PathBuf>,
    pub ignored_settings: Vec<String>,
    pub path_issues: Vec<String>,
}

impl ConversionWarnings {
    pub fn new() -> Self {
        Self {
            missing_files: Vec::new(),
            ignored_settings: Vec::new(),
            path_issues: Vec::new(),
        }
    }
    
    pub fn add_missing_file(&mut self, path: PathBuf) {
        self.missing_files.push(path);
    }
    
    pub fn add_ignored_setting(&mut self, setting: String) {
        self.ignored_settings.push(setting);
    }
    
    pub fn add_path_issue(&mut self, issue: String) {
        self.path_issues.push(issue);
    }
    
    pub fn has_warnings(&self) -> bool {
        !self.missing_files.is_empty() || 
        !self.ignored_settings.is_empty() || 
        !self.path_issues.is_empty()    }
}

/// 添加上下文信息到错误
pub trait ResultExt<T> {
    fn with_context<C, F>(self, context: F) -> Result<T, anyhow::Error>
    where
        C: Into<String>,
        F: FnOnce() -> C;
}

impl<T, E: Into<anyhow::Error>> ResultExt<T> for Result<T, E> {
    fn with_context<C, F>(self, context: F) -> Result<T, anyhow::Error>
    where
        C: Into<String>,
        F: FnOnce() -> C,
    {
        self.map_err(|err| {
            let context = context().into();
            anyhow::anyhow!("{}: {}", context, err.into())
        })
    }
} 